<template>
  <div class="color-picker" @click.stop id="target">
    <!-- 颜色预览和触发器 -->
    <div
      class="color-preview"
      :style="{ backgroundColor: currentColor }"
      @click="togglePicker"
    >
      <span class="color-value">{{ currentColor || "请选择颜色" }}</span>
      <i class="fa fa-chevron-down" :class="{ rotate: isOpen }"></i>
    </div>

    <!-- 颜色选择面板 -->
    <div
      class="color-panel"
      v-if="isOpen"
      :style="{ top: panelTop + 'px', left: panelLeft + 'px' }"
    >
      <!-- 颜色选择区域 -->
      <div
        class="color-area"
        ref="colorArea"
        @mousedown="startSelecting('area')"
      >
        <div class="color-overlay"></div>
        <div
          class="color-indicator"
          :style="{ top: indicatorY + 'px', left: indicatorX + 'px' }"
        ></div>
      </div>

      <!-- 色相选择条 -->
      <div
        class="hue-slider"
        ref="hueSlider"
        @mousedown="startSelecting('hue')"
      >
        <div class="hue-indicator" :style="{ top: hueY + 'px' }"></div>
      </div>

      <!-- 透明度选择条 -->
      <div
        class="alpha-slider"
        ref="alphaSlider"
        @mousedown="startSelecting('alpha')"
      >
        <div
          class="alpha-background"
          :style="{ backgroundColor: currentColorWithoutAlpha }"
        ></div>
        <div class="alpha-overlay"></div>
        <div class="alpha-indicator" :style="{ top: alphaY + 'px' }"></div>
      </div>

      <!-- 颜色输入 -->
      <div class="color-inputs">
        <input
          type="text"
          v-model="colorInput"
          @input="handleColorInput"
          placeholder="#RRGGBB"
        />
        <div class="preset-colors">
          <div
            v-for="(color, index) in presetColors"
            :key="index"
            :style="{ backgroundColor: color }"
            @click="selectPresetColor(color)"
            :title="color"
          ></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "ColorPicker",
  props: {
    // 初始颜色值
    value: {
      type: String,
      default: "#ffffff"
    },
    // 预设颜色列表
    presetColors: {
      type: Array,
      default: () => [
        "#000000",
        "#ffffff",
        "#ff0000",
        "#00ff00",
        "#0000ff",
        "#ffff00",
        "#ff00ff",
        "#00ffff",
        "#ff9900",
        "#9900ff"
      ]
    }
  },
  data() {
    return {
      isOpen: false,
      currentColor: this.value,
      colorInput: this.value,
      // 颜色选择器位置
      panelTop: 0,
      panelLeft: 0,
      // 颜色指示器位置
      indicatorX: 0,
      indicatorY: 0,
      hueY: 0,
      alphaY: 0,
      // 颜色值
      hsl: { h: 0, s: 100, l: 50, a: 1 },
      selecting: null
    };
  },
  computed: {
    // 当前颜色（不带透明度）
    currentColorWithoutAlpha() {
      return this.currentColor.replace(
        /rgba?(\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*)(,\s*[\d.]+)?\s*\)/,
        "rgb$1)"
      );
    }
  },
  watch: {
    value(newVal) {
      this.currentColor = newVal;
      this.colorInput = newVal;
      this.parseColor(newVal);
    },
    currentColor(newVal) {
      this.$emit("input", newVal);
      this.$emit("change", newVal);
      this.colorInput = newVal;
    }
  },
  mounted() {
    this.parseColor(this.value);
    document.addEventListener("mousemove", this.handleMouseMove);
    document.addEventListener("mouseup", this.handleStopSelecting);
    // 获取需要监听外部点击的元素
    const targetElement = document.getElementById("target");
    // 监听全局点击事件
    document.addEventListener("click", event => {
      // 判断点击目标是否是目标元素或其内部元素
      if (!targetElement.contains(event.target)) {
        this.isOpen = false;
      }
    });
  },
  beforeDestroy() {
    document.removeEventListener("mousemove", this.handleMouseMove);
    document.removeEventListener("mouseup", this.handleStopSelecting);
  },
  methods: {
    // 切换颜色选择面板显示状态
    togglePicker() {
      this.isOpen = !this.isOpen;
      if (this.isOpen) {
        this.calculatePanelPosition();
      }
    },

    // 计算面板位置
    calculatePanelPosition() {
      const rect = this.$el.getBoundingClientRect();
      this.panelTop = rect.height;
      this.panelLeft = 0;
    },

    // 开始选择颜色
    startSelecting(type) {
      this.selecting = type;
      event.preventDefault();
    },

    // 停止选择颜色
    handleStopSelecting() {
      this.selecting = null;
    },

    // 处理鼠标移动
    handleMouseMove(event) {
      if (!this.selecting) return;

      switch (this.selecting) {
        case "area":
          this.handleAreaMouseMove(event);
          break;
        case "hue":
          this.handleHueMouseMove(event);
          break;
        case "alpha":
          this.handleAlphaMouseMove(event);
          break;
      }
    },

    // 处理颜色区域鼠标移动
    handleAreaMouseMove(event) {
      const rect = this.$refs.colorArea.getBoundingClientRect();
      let x = event.clientX - rect.left;
      let y = event.clientY - rect.top;

      // 限制在区域内
      x = Math.max(0, Math.min(x, rect.width));
      y = Math.max(0, Math.min(y, rect.height));

      this.indicatorX = x;
      this.indicatorY = y;

      // 计算饱和度和亮度
      const s = (x / rect.width) * 100;
      const l = 100 - (y / rect.height) * 100;

      this.hsl.s = s;
      this.hsl.l = l;
      this.updateColorFromHsl();
    },

    // 处理色相条鼠标移动
    handleHueMouseMove(event) {
      const rect = this.$refs.hueSlider.getBoundingClientRect();
      let y = event.clientY - rect.top;

      // 限制在条内
      y = Math.max(0, Math.min(y, rect.height));
      this.hueY = y;

      // 计算色相
      const h = 360 - (y / rect.height) * 360;
      this.hsl.h = h;
      this.updateColorFromHsl();
    },

    // 处理透明度条鼠标移动
    handleAlphaMouseMove(event) {
      const rect = this.$refs.alphaSlider.getBoundingClientRect();
      let y = event.clientY - rect.top;

      // 限制在条内
      y = Math.max(0, Math.min(y, rect.height));
      this.alphaY = y;

      // 计算透明度
      const a = 1 - y / rect.height;
      this.hsl.a = a;
      this.updateColorFromHsl();
    },

    // 从HSL更新颜色
    updateColorFromHsl() {
      const { h, s, l, a } = this.hsl;
      let color = this.hslToHex(h, s, l);

      // 如果透明度不是1，使用rgba
      if (a < 1) {
        const rgb = this.hexToRgb(color);
        color = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${a.toFixed(2)})`;
      }

      this.currentColor = color;
    },

    // 解析颜色值
    parseColor(color) {
      // 处理十六进制颜色
      if (color.match(/^#/)) {
        this.handleHexColor(color);
      }
      // 处理rgb颜色
      else if (color.match(/^rgb/)) {
        this.handleRgbColor(color);
      }
    },

    // 处理十六进制颜色
    handleHexColor(hex) {
      // 确保 hex 是有效的
      hex = hex.replace(/^#/, "");
      if (hex.length === 3) {
        hex = hex
          .split("")
          .map(c => c + c)
          .join("");
      }

      if (hex.length === 6) {
        const rgb = this.hexToRgb(`#${hex}`);
        const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);

        this.hsl = { ...hsl, a: 1 };
        this.updateIndicators();
      }
    },

    // 处理RGB颜色
    handleRgbColor(rgbStr) {
      const rgbMatch = rgbStr.match(
        /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/
      );

      if (rgbMatch) {
        const r = parseInt(rgbMatch[1]);
        const g = parseInt(rgbMatch[2]);
        const b = parseInt(rgbMatch[3]);
        const a = rgbMatch[4] ? parseFloat(rgbMatch[4]) : 1;

        const hsl = this.rgbToHsl(r, g, b);
        this.hsl = { ...hsl, a };
        this.updateIndicators();
      }
    },

    // 更新指示器位置
    updateIndicators() {
      const { h, s, l, a } = this.hsl;

      // 更新颜色区域指示器
      if (this.$refs.colorArea) {
        const rect = this.$refs.colorArea.getBoundingClientRect();
        this.indicatorX = (s / 100) * rect.width;
        this.indicatorY = ((100 - l) / 100) * rect.height;
      }

      // 更新色相条指示器
      if (this.$refs.hueSlider) {
        const rect = this.$refs.hueSlider.getBoundingClientRect();
        this.hueY = (1 - h / 360) * rect.height;
      }

      // 更新透明度条指示器
      if (this.$refs.alphaSlider) {
        const rect = this.$refs.alphaSlider.getBoundingClientRect();
        this.alphaY = (1 - a) * rect.height;
      }
    },

    // 处理颜色输入
    handleColorInput() {
      const value = this.colorInput.trim();
      if (this.isValidColor(value)) {
        this.currentColor = value;
        this.parseColor(value);
      }
    },

    // 选择预设颜色
    selectPresetColor(color) {
      this.currentColor = color;
      this.parseColor(color);
    },

    // 验证颜色是否有效
    isValidColor(color) {
      const dummy = document.createElement("div");
      dummy.style.color = color;
      return dummy.style.color !== "";
    },

    // RGB转HSL
    rgbToHsl(r, g, b) {
      r /= 255;
      g /= 255;
      b /= 255;

      const max = Math.max(r, g, b);
      const min = Math.min(r, g, b);
      let h,
        s,
        l = (max + min) / 2;

      if (max === min) {
        h = s = 0; // 灰度
      } else {
        const d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

        switch (max) {
          case r:
            h = (g - b) / d + (g < b ? 6 : 0);
            break;
          case g:
            h = (b - r) / d + 2;
            break;
          case b:
            h = (r - g) / d + 4;
            break;
        }

        h *= 60;
      }

      return { h, s: s * 100, l: l * 100 };
    },

    // HSL转十六进制
    hslToHex(h, s, l) {
      s /= 100;
      l /= 100;

      let r, g, b;

      if (s === 0) {
        r = g = b = l; // 灰度
      } else {
        const hue2rgb = (p, q, t) => {
          if (t < 0) t += 1;
          if (t > 1) t -= 1;
          if (t < 1 / 6) return p + (q - p) * 6 * t;
          if (t < 1 / 2) return q;
          if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
          return p;
        };

        const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        const p = 2 * l - q;

        r = hue2rgb(p, q, h / 360 + 1 / 3);
        g = hue2rgb(p, q, h / 360);
        b = hue2rgb(p, q, h / 360 - 1 / 3);
      }

      const toHex = x => {
        const hex = Math.round(x * 255).toString(16);
        return hex.length === 1 ? "0" + hex : hex;
      };

      return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
    },

    // 十六进制转RGB
    hexToRgb(hex) {
      const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
      return result
        ? {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16)
          }
        : null;
    }
  }
};
</script>

<style scoped>
.color-picker {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

/* 颜色预览和触发器 */
.color-preview {
  position: relative;
  width: 120px;
  height: 40px;
  border-radius: 4px;
  border: 1px solid #ddd;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 10px;
  box-sizing: border-box;
  transition: all 0.2s ease;
}

.color-preview:hover {
  border-color: #999;
}

.color-value {
  font-size: 14px;
  color: #333;
  text-shadow: 0 0 2px rgba(255, 255, 255, 0.5);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 70px;
}

.fa-chevron-down {
  transition: transform 0.2s ease;
  color: #666;
}

.rotate {
  transform: rotate(180deg);
}

/* 颜色选择面板 */
.color-panel {
  position: absolute;
  z-index: 1000;
  width: 250px;
  background: #fff;
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  padding: 15px;
  box-sizing: border-box;
  margin-top: 5px;
}

/* 颜色选择区域 */
.color-area {
  position: relative;
  width: 100%;
  height: 200px;
  background: linear-gradient(to right, #fff, #f00);
  border-radius: 4px;
  margin-bottom: 15px;
  cursor: crosshair;
}

.color-overlay {
  width: 100%;
  height: 100%;
  background: linear-gradient(to top, #000, transparent);
  border-radius: 4px;
}

.color-indicator {
  position: absolute;
  width: 12px;
  height: 12px;
  border: 2px solid #fff;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
}

/* 色相选择条 */
.hue-slider {
  position: relative;
  width: 100%;
  height: 10px;
  background: linear-gradient(
    to bottom,
    #ff0000 0%,
    #ffff00 16.67%,
    #00ff00 33.33%,
    #00ffff 50%,
    #0000ff 66.67%,
    #ff00ff 83.33%,
    #ff0000 100%
  );
  border-radius: 5px;
  margin-bottom: 15px;
  cursor: pointer;
}

.hue-indicator {
  position: absolute;
  left: -3px;
  width: 16px;
  height: 3px;
  border: 2px solid #fff;
  border-radius: 2px;
  transform: translateY(-50%);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
}

/* 透明度选择条 */
.alpha-slider {
  position: relative;
  width: 100%;
  height: 10px;
  border-radius: 5px;
  margin-bottom: 15px;
  cursor: pointer;
}

.alpha-background {
  width: 100%;
  height: 100%;
  border-radius: 5px;
}

.alpha-overlay {
  width: 100%;
  height: 100%;
  background: linear-gradient(to right, transparent, #000);
  border-radius: 5px;
}

.alpha-indicator {
  position: absolute;
  left: -3px;
  width: 16px;
  height: 3px;
  border: 2px solid #fff;
  border-radius: 2px;
  transform: translateY(-50%);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
}

/* 颜色输入和预设 */
.color-inputs {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.color-inputs input {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
  box-sizing: border-box;
}

.color-inputs input:focus {
  outline: none;
  border-color: #66afe9;
  box-shadow: 0 0 0 2px rgba(102, 175, 233, 0.25);
}

.preset-colors {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.preset-colors div {
  width: 24px;
  height: 24px;
  border-radius: 4px;
  cursor: pointer;
  transition: transform 0.1s ease;
  border: 1px solid #eee;
}

.preset-colors div:hover {
  transform: scale(1.1);
}
</style>
